package belf.migrate.engine.job.structure;

import belf.migrate.api.taskconf.JobContext;
import belf.migrate.api.taskconf.TaskConf;
import belf.migrate.api.type.LogLevelType;
import belf.migrate.api.type.MigrationObjectType;
import belf.migrate.api.util.PostLog;
import belf.migrate.api.job.Job;
import belf.migrate.engine.job.JobResult;
import belf.migrate.engine.job.structure.helper.*;
import belf.migrate.api.taskconf.Task;
import com.google.gson.JsonArray;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;

import static belf.migrate.api.job.JobCode.EXECUTING;
import static belf.migrate.api.job.JobCode.SUCCESS;

/**
 * 异构数据库之间同步以下结构信息：TYPE，TABLE，VIEW，SEQ、TRIGGER。同义词、存储过程暂时没有处理。<br/>
 * 所有子任务共享一个JobContext，减少资源开销，提升速率。所有子任务的执行结果一并返回，方便页面展示结果。
 */
@Slf4j
public class SyncAllStucture {
    private Job job;
    private Task task;
    private TaskConf taskConf;
    private JobContext jobContext;
    /**
     * 保存要执行的任务类型，参考{@link Task.TaskType}
     */
    private List<Task.TaskType> taskTypes = new ArrayList<>();
    //以下是默认的任务配置
    private boolean createSynonym = false;             //是否同步同义词
    private boolean createType = false;                //是否同步TYPE
    private boolean createSeq = false;                 //是否同步序列
    private boolean createFunction = false;            //是否同步函数
    private boolean createTable = true;                //是否同步表
    private boolean createForeignKey = false;          //是否同步外键
    private boolean createView = false;                //是否同步视图
    private boolean createTrigger = false;             //是否同步触发器
    private boolean createProcedure = false;           //是否同步存储过程


    public SyncAllStucture(Job job) {
        this.job = job;
        this.task = job.getTask();
        this.taskConf = task.getTaskConf();

        if (StringUtils.isNotEmpty(task.getTaskTypeScope())) {
            String[] taskTypeScopes = task.getTaskTypeScope().split(",");
            for (String str : taskTypeScopes) {
                Task.TaskType taskType = Task.TaskType.valueOf(str);
                taskTypes.add(taskType);
            }
        }

        if (!taskTypes.isEmpty()) {
            for (Task.TaskType taskType : taskTypes) {
                if (taskType == Task.TaskType.CREATE_SYNONYM) {
                    createSynonym = true;
                } else if (taskType == Task.TaskType.CREATE_TYPE) {
                    createType = true;
                } else if (taskType == Task.TaskType.CREATE_SEQ) {
                    createSeq = true;
                } else if (taskType == Task.TaskType.CREATE_FUNCTION) {
                    createFunction = true;
                } else if (taskType == Task.TaskType.CREATE_TABLE) {
                    createTable = true;
                } else if (taskType == Task.TaskType.CREATE_FOREIGNKEY) {
                    createForeignKey = true;
                } else if (taskType == Task.TaskType.CREATE_VIEW) {
                    createView = true;
                } else if (taskType == Task.TaskType.CREATE_TRIGGER) {
                    createTrigger = true;
                } else if (taskType == Task.TaskType.CREATE_PROCEDURE) {
                    createProcedure = true;
                }
            }
        }

        log.info("SYNC_STRUCTURE参数配置：");
        log.info("createSynonym：   {}", createSynonym);
        log.info("createType：      {}", createType);
        log.info("createSeq：       {}", createSeq);
        log.info("createFunction：  {}", createFunction);
        log.info("createTable：     {}", createTable);
        log.info("createForeignKey：{}", createForeignKey);
        log.info("createView：      {}", createView);
        log.info("createTrigger：   {}", createTrigger);
        log.info("createProcedure： {}", createProcedure);
    }

    public JobResult execute() {

        JobResult executedResult = new JobResult(SUCCESS, "同步所有结构开始Job提交成功。");
        JsonArray items = new JsonArray();
        StructureJobRunner structureJobRunner = new StructureJobRunner(job, createTable, false, createForeignKey);
        //初始化JobContext
        structureJobRunner.check();
        this.jobContext = structureJobRunner.getJobContext(); //所有子任务复用一个jobContext

        jobContext.setTotalProgress(taskTypes.size());
        PostLog.sendLogModel(
                job.getJobId(),
                job.getTask().getTaskType().getName(),
                "同步所有结构开始！",
                LogLevelType.INFO.getType(),
                EXECUTING,
                jobContext.getProgress());

        JobResult result = null;
        if (createSynonym) {
            result = new CreateSynonymTool(job, jobContext).run();
            result.setTypeName(MigrationObjectType.SYNONYM.getName());
            items.add(result.toJson());
        }

        if (createType) {
            result = new CreateTypeTool(job, jobContext).run();
            result.setTypeName(MigrationObjectType.TYPE.getName());
            items.add(result.toJson());
        }

        if (createSeq) {
            result = new CreateSeqTool(job, jobContext).run();
            result.setTypeName(MigrationObjectType.SEQUENCE.getName());
            items.add(result.toJson());
        }

        if (createTable) {//允许同事创建外键
            result = structureJobRunner.execute();
            result.setTypeName(MigrationObjectType.TABLE_STRUCTURE.getName());
            items.add(result.toJson());
        }

        if (createView) {
            result = new CreateViewTool(job, jobContext).run();
            result.setTypeName(MigrationObjectType.VIEW.getName());
            items.add(result.toJson());
        }


        if (createFunction) {
            result = new CreateFunctionTool(job, jobContext).run();
            result.setTypeName(MigrationObjectType.FUNCTION.getName());
            items.add(result.toJson());
        }

        if (createProcedure) {
            result = new CreateProcedureTool(job, jobContext).run();
            result.setTypeName(MigrationObjectType.PROCEDURE.getName());
            items.add(result.toJson());
        }

        if (createTrigger) {
            result = new CreateTriggerTool(job, jobContext).run();
            result.setTypeName(MigrationObjectType.TRIGGER.getName());
            items.add(result.toJson());
        }

        PostLog.sendLogModel(
                job.getJobId(),
                job.getTask().getTaskType().getName(),
                "同步所有结构结束！",
                LogLevelType.INFO.getType(),
                EXECUTING,
                jobContext.getProgress());
        executedResult.setData(items);
        return executedResult;
    }

    public Job getJob() {
        return job;
    }

}
